#pragma once

#include <iostream>
#include <vector>
#include <functional>

#include "InetAddr.hpp"
#include "ThreadPool.hpp"

using namespace std;
using task_t=function<void()>;

class MessageRoute
{
private:
    bool IsExist(const InetAddr& addr)
    {
        vector<InetAddr>::iterator it=_online_user.begin();
        while(it!=_online_user.end())
        {
            if(*it==addr)
            {
                return true;
                break;
            }
            ++it;
        }
        return false;
    }
public:
    MessageRoute()
    {

    }

    void AddUser(const InetAddr& user)
    {
        if(IsExist(user)) return;
        _online_user.push_back(user);
    }

    void DelUser(const InetAddr& user)
    {

        vector<InetAddr>::iterator it=_online_user.begin();
        while(it!=_online_user.end())
        {
            if(*it==user)
            {
                _online_user.erase(it);
                break;
            }
            ++it;
        }

    }

    void RouteHelper(int sockfd,const string message,InetAddr who)
    {

        //消息转发到所有在线用户  
        for(auto u:_online_user)
        {
            //构建消息的输出格式 [ip:port]# message "\n"
            string sendmessage="["+who.IP()+":"+to_string(who.Port())+"]# "+message+"\n";

            struct sockaddr_in addr=u.SockAddr();
            sendto(sockfd,sendmessage.c_str(),sendmessage.size(),0,(struct sockaddr*)&addr,sizeof(addr));
        }

    }

    void Route(int sockfd,const string message,InetAddr user)//消息转发
    {
       

        AddUser(user);

        if("Q"==message.c_str()|"QUIT"==message.c_str())
        {
            DelUser(user);
        }

        //目标:线程池进行消息转发
        //线程池执行逻辑:线程池内部的线程从任务队列中获取任务,获取到任务后的任务的执行方式为t();
        //线程池转发消息的方案:
        //1.将消息内容打包成一个任务对象,将任务对象入队列---构建任务对象
        //2.线程池执行任务的方式为t(),MessageRoute::Route()参数无法满足要求,需要单独涉及接口MessageRoute::RouteHelper()

        //<1> 构建任务对象 线程池为模板类,入队列的数据类型为T
        // using task_t=function<void()>;
        // task_t task;
        // ThreadPool<task_t>::GetInstance->Enqueue(task);
        // task中应该包含消息内容,但是类型只能为void task(),使用函数适配器bind解决

        task_t task=std::bind(&MessageRoute::RouteHelper,this,sockfd,message,user);
        ThreadPool<task_t>::GetInstance()->Enqueue(task);
        
    }
    ~MessageRoute()
    {
       
    }
private:
    vector<InetAddr> _online_user;//采用客户端的IP地址与端口号标识用户的唯一性

};